package org.testis.gui.mvc.utilities;

import java.io.CharArrayReader;
import java.io.IOException;
import java.io.Reader;
import java.util.LinkedList;
import java.util.Locale;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.testis.utils.middleware.DynamicMapAbstractionPairs;
import org.testis.utils.parametermodel.ParameterModel;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;


/**
 *
 * @author nurhat
 */
public class PageXmlParser
{

    public LinkedList<PageParserObject> parseXmlString(String input) throws
        SAXException, IOException,
        ParserConfigurationException
    {


        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        Reader reader = new CharArrayReader(input.toCharArray());
        Document doc = builder.parse(new org.xml.sax.InputSource(reader));
        /*  
        TransformerFactory tranFact = TransformerFactory.newInstance();
        Transformer transfor = tranFact.newTransformer();
        Node node = doc.getDocumentElement();
        Source src = new DOMSource(node);
        Result dest = new StreamResult(System.out);
        transfor.transform(src, dest);
         */

        Element docEle = doc.getDocumentElement();
        LinkedList<PageParserObject> objectList =
            new LinkedList<PageParserObject>();
        if (docEle.getNodeName().equals("UIAll")) {
            NodeList elements = docEle.getChildNodes();
            for (int i = 0; i < elements.getLength(); i++) {
                LinkedList<PageParserObject> tmpList = parseObjects(
                    (Element) elements.item(i));
                objectList.addAll(tmpList);
            }
        }
        else {
            LinkedList<PageParserObject> tmpList = parseObjects(docEle);
            objectList.addAll(tmpList);
        }
        System.out.println("Printing  objects");
        for (int i = 0; i < objectList.size(); i++) {
            System.out.println(objectList.get(i).getType());
            String realName = objectList.get(i).getParameterByName("id");
            if (realName == null) {
                realName = objectList.get(i).
                    getParameterByName("name");
            }
            realName = clearCdataTag(realName);
            objectList.get(i).setRealName(realName);
            System.out.println(objectList.get(i).getRealName());
            if (objectList.get(i).getChilds().size() > 0) {
                System.out.println("\t" + "Printing child objects");
                for (int j = 0; j < objectList.get(i).getChilds().size(); j++) {
                    System.out.println("\t" + objectList.get(i).getChilds().get(
                                       j).
                                       getType());
                    realName = objectList.get(i).getChilds().get(j).
                        getParameterByName("id");
                    if (realName == null) {
                        realName = objectList.get(i).getChilds().get(j).
                            getParameterByName("name");
                    }
                    realName = clearCdataTag(realName);
                    objectList.get(i).getChilds().get(j).setRealName(realName);
                    System.out.println("\t" + objectList.get(i).getChilds().get(
                                       j).
                                       getRealName());
                }
            }
        }

        return objectList;
    }


    private String clearCdataTag(String input)
    {
        if (input == null) {
            return "";
        }
        return input.replace("<![CDATA[",
                             "").replace("]]>",
                                         "");
    }


    private LinkedList<PageParserObject> parseObjects(Element root)
    {
        LinkedList<PageParserObject> objectList =
            new LinkedList<PageParserObject>();
        NodeList elements = root.getElementsByTagName("element");
        if (elements == null || elements.getLength() <= 0) {
            return objectList;
        }
        for (int i = 0; i < elements.getLength(); i++) {
            PageParserObject object = new PageParserObject();
            object.setType(root.getNodeName());

            Element curElement = (Element) elements.item(i);
            NodeList curAttributesList = curElement.getElementsByTagName(
                "attributes");
            NodeList curOptionsList = curElement.getElementsByTagName(
                "options");
            parseAttributes(curAttributesList,
                            object);
            parseOptions(curOptionsList,
                         object);
            if (object.getParameterByName("Id") != null) {
                DynamicMapAbstractionPairs pairs =
                    new DynamicMapAbstractionPairs();
                String absId = "__asp" + object.getParameterByName("Id");
                String tmpId=absId;
                int index = 0;
                while (pairs.IsAbstractIdExist(tmpId)) {
                    tmpId = absId + "_" + index;
                    index++;
                }
                object.addParameter(
                    "AbstractId",
                    tmpId);
            }
            else {
                object.addParameter(
                    "AbstractId",
                    "");
            }
            objectList.add(object);
        }
        return objectList;
    }


    private void parseAttributes(NodeList curAttributesList,
                                 PageParserObject object)
    {
        String nodeName,
          nodeValue;
        if (curAttributesList != null && curAttributesList.getLength() >
            0) {
            Element curAttributes = (Element) curAttributesList.item(0);
            NodeList attributeValues = curAttributes.getChildNodes();
            for (int j = 0; j < attributeValues.getLength(); j++) {
                nodeName = attributeValues.item(j).
                    getNodeName();

                nodeValue = attributeValues.item(j).
                    getTextContent();
                nodeName = clearCdataTag(nodeName).toLowerCase(
                    Locale.ENGLISH);
                nodeValue = clearCdataTag(nodeValue);
                nodeName = getValidNodeName(nodeName);
                ParameterModel model =
                    new ParameterModel(nodeName,
                                       nodeValue.trim());
                object.addParameter(model);
            }
        }
    }


    private void parseOptions(NodeList curOptionsList,
                              PageParserObject object)
    {
        String nodeName,
          nodeValue;
        if (curOptionsList != null && curOptionsList.getLength() > 0) {
            Element curOptions =
                (Element) curOptionsList.item(0);
            NodeList optionValues = curOptions.getChildNodes();
            for (int j = 0; j < optionValues.getLength(); j++) {
                Element curOption = (Element) optionValues.item(j);
                String type = curOption.getAttribute("type");
                PageParserObject optionObject = new PageParserObject();
                optionObject.setType(type);
                NodeList optionAttributeValues =
                    curOption.getChildNodes();
                for (int k = 0; k < optionAttributeValues.getLength();
                    k++) {
                    nodeName = optionAttributeValues.item(k).
                        getNodeName();
                    nodeValue = optionAttributeValues.item(k).
                        getTextContent();
                    nodeName = clearCdataTag(nodeName).toLowerCase(
                        Locale.ENGLISH);
                    nodeValue = clearCdataTag(nodeValue);
                    nodeName = getValidNodeName(nodeName);
                    ParameterModel model =
                        new ParameterModel(nodeName,
                                           nodeValue.trim());
                    optionObject.addParameter(model);
                }
                object.addChild(optionObject);
            }
        }
    }


    private String getValidNodeName(String nodeName)
    {
        if (nodeName.equals("id")) {
            return "Id";
        }
        else if (nodeName.equals("name")) {
            return "Name";
        }
        else if (nodeName.equals("xpath")) {
            return "Xpath";
        }
        else if (nodeName.equals("value")) {
            return "Value";
        }
        else if (nodeName.equals("label")) {
            return "Label";
        }
        else if (nodeName.equals("innerhtml")) {
            return "Value";
        }
        else if (nodeName.equals("href")) {
            return "Url";
        }
        return nodeName;
    }
}
